<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */

namespace App\Listener;

use Hyperf\Collection\Arr;
use Hyperf\Database\Events\ConnectionEvent;
use Hyperf\Database\Events\QueryExecuted;
use Hyperf\Database\Events\StatementPrepared;
use Hyperf\Database\Events\TransactionBeginning;
use Hyperf\Database\Events\TransactionCommitted;
use Hyperf\Database\Events\TransactionRolledBack;
use Hyperf\Event\Annotation\Listener;
use Hyperf\Event\Contract\ListenerInterface;
use Psr\Log\LoggerInterface;
use Xin\Logger\Logger;
use function Hyperf\Config\config;

#[Listener]
class OnDbListener implements ListenerInterface
{
    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * DbQueryExecutedListener constructor.
     */
    public function __construct()
    {
        $this->logger = Logger::logger('sql')->enableStdout();
    }

    /**
     * @return \class-string[]
     */
    public function listen(): array
    {
        return [
            ConnectionEvent::class,
            QueryExecuted::class,
            StatementPrepared::class,
            TransactionBeginning::class,
            TransactionCommitted::class,
            TransactionRolledBack::class,
        ];
    }

    /**
     * @param object $event
     * @return void
     */
    public function process(object $event): void
    {
        if ($event instanceof QueryExecuted) {
            $this->queryExecuted($event);
        }
    }

    /**
     * @param QueryExecuted $event
     * @return void
     */
    public function queryExecuted(QueryExecuted $event)
    {
        $sql = $event->sql;
        if (!Arr::isAssoc($event->bindings)) {
            $position = 0;
            foreach ($event->bindings as $value) {
                $position = strpos($sql, '?', $position);
                if ($position === false) {
                    break;
                }
                $value = is_string($value) ? "'{$value}'" : "$value";
                $sql = substr_replace($sql, $value, $position, 1);
                $position += strlen($value);
            }
        }

        $logMethod = config('sql_debug') ? 'info' : 'debug';
        $this->logger->{$logMethod}(sprintf('[%s] %s', $event->time, $sql));
    }
}
